package com.woniu.tmsorder.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woniu.tmscommons.entity.*;
import com.woniu.tmscommons.enums.OrderStatusEnum;
import com.woniu.tmscommons.enums.PayStatusEnum;
import com.woniu.tmscommons.exception.KillException;
import com.woniu.tmscommons.feign.FeignTransportService;
import com.woniu.tmscommons.utils.OrderNoUtil;
import com.woniu.tmsorder.config.RabbitConfig;
import com.woniu.tmsorder.listener.DriverStatusListener;
import com.woniu.tmsorder.mapper.OrderMapper;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import com.woniu.tmsorder.mapper.SenderReceiverMapper;
import com.woniu.tmsorder.pojo.Message;
import com.woniu.tmsorder.service.*;
import com.woniu.tmsorder.vo.*;
import io.seata.spring.annotation.GlobalTransactional;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class OrderServiceImpl implements OrderService {
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private SenderReceiverService senderReceiverService;
    @Resource
    private BillService billService;
    @Resource
    private PricingRuleService pricingRuleService;
    @Resource
    private OrderItemService orderItemService;
    @Resource
    private FeignTransportService feignTransportService;
    @Value("${spring.mail.username}")
    private String email;


    @GlobalTransactional
//    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(OrderVo vo) {
        System.out.println("距离" + vo.getDistance());
        SenderReceiver senderReceiver = vo.getSenderReceiver();
        // 生成发件人、收件人信息
        senderReceiverService.add(senderReceiver);
        //获取单价
        PricingRuleVo pricingRuleVo = new PricingRuleVo(vo.getVehicleTypeId(), vo.getDistance());
        BigDecimal unitPrice = pricingRuleService.getUnitPrice(pricingRuleVo);
        // 生成账单
        Bill bill = addBill(vo.getIsUrgent(), vo.getIsInsurance(), vo.getIsRefrigerated(), vo.getTotalWorth(), vo.getDistance(), unitPrice);
        billService.add(bill);
        Order order = new Order();
        order.setOrderNo(OrderNoUtil.getOrderNo());
        order.setCreatedAt(LocalDateTime.now());
        order.setUpdatedAt(LocalDateTime.now());
        order.setStatus(OrderStatusEnum.PENDING);
        order.setDriverId(vo.getDriverId());
        order.setSenderReceiverId(senderReceiver.getId());
        order.setVehicleId(vo.getVehicleId());
        order.setTotalWeight(vo.getTotalWeight());
        order.setDistance(vo.getDistance());
        order.setTotalWorth(vo.getTotalWorth());
        order.setIsRefrigerated(vo.getIsRefrigerated());
        order.setIsInsurance(vo.getIsInsurance());
        order.setIsUrgent(vo.getIsUrgent());
        order.setBillId(bill.getId());
        // 生成订单
        orderMapper.insert(order);
        //生成订单详情
        List<OrderItem> orderItem = vo.getOrderItems();
        for (OrderItem item : orderItem) {
            item.setOrderId(order.getId());
            orderItemService.add(item);
        }
        updateStatusService.updateDriverAndVehicleStatusOfAfterStartOrder(vo.getVehicleId(), vo.getDriverId());
//        String driverEmail = updateStatusService.findDriverTypeAndEmail(vo.getDriverId());

        Message message = new Message();
        message.setToEmail(email);
        message.setMessage("您好，已经为你分配新的订单,请及时完成运输");
        rabbitTemplate.convertAndSend(RabbitConfig.EMAIL_EXCHANGE,"",message);
    }

    @Override
    public OrderVo findByOrderNo(String orderNo) {
        return orderMapper.findByOrderNo(orderNo);
    }

    @Override
    public void deleteByOrderNo(String orderNo) {
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Order::getOrderNo, orderNo);
        Order order = orderMapper.selectOne(queryWrapper);
        Integer orderId = order.getId();
        // 删除账单、订单详情、发件人、收件人
        billService.deleteById(order.getBillId());
        orderItemService.deleteByOrderId(orderId);
        senderReceiverService.deleteById(order.getSenderReceiverId());
        // 删除订单
        orderMapper.deleteByOrderNo(orderNo);
    }

    @Override
    public void update(Order order) {
        LambdaUpdateWrapper<Order> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Order::getOrderNo, order.getOrderNo());
        orderMapper.update(order, updateWrapper);
    }

    @Override
    public IPage<List<OrderVo>> findAll(PageVo o) {
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq((o.getOrder().getDriverId() != null&&o.getOrder().getDriverId() != 0), Order::getDriverId, o.getOrder().getDriverId());
        Long aLong=orderMapper.selectCount(queryWrapper);
        System.out.println(aLong);
        Page<OrderVo> page = new Page<>(o.getPageNum(), o.getPageSize());
        IPage<List<OrderVo>> listAndPage = orderMapper.findListAndPage(page, o.getOrder());
        listAndPage.setTotal(aLong);
        return listAndPage;
    }

    /**
     * 匹配车辆
     */
    @Override
    public AutoAllocatipnVo autoAllocation(ConditionVo conditionVo) {
        AutoAllocatipnVo autoAllocatipnVo = new AutoAllocatipnVo();
        // 获取最合适的车辆
        Vehicle vehicle = feignTransportService.findRightVehicle(conditionVo.getTotalWeight(),conditionVo.getSenderAddress()).getData();
        if (vehicle != null) {
            PricingRuleVo pricingRuleVo = new PricingRuleVo(vehicle.getVehicleTypeId(), conditionVo.getDistance());
            // 获取单价
            BigDecimal unitPrice = pricingRuleService.getUnitPrice(pricingRuleVo);
            autoAllocatipnVo.setUnitPrice(unitPrice);
            if (vehicle.getDriverId() == null) {
                autoAllocatipnVo.setDriver(null);
                Bill bill = addBill(conditionVo.getIsUrgent(), conditionVo.getIsInsurance(), conditionVo.getIsRefrigerated(), conditionVo.getTotalWorth(), conditionVo.getDistance(), unitPrice);
                billService.add(bill);
                autoAllocatipnVo.setBillId(bill.getId());
            } else {
                // 获取最合适的司机
                Driver driver = vehicle.getDriver();
                driver.setId(vehicle.getDriverId());
                autoAllocatipnVo.setDriver(driver);
            }
            autoAllocatipnVo.setVehicle(vehicle);

            return autoAllocatipnVo;
        };
        return null;
    }

    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    private static final long TIMEOUT = 60*5 ;

    /**
     * 发布到广场的订单(丢到redis缓冲池列表)
     * @param vo
     */
    @Override
    public void addOther(OrderVo vo) {
        SenderReceiver senderReceiver = vo.getSenderReceiver();
        // 生成发件人、收件人信息
        senderReceiverService.add(senderReceiver);
        Order order = new Order();
        order.setOrderNo(OrderNoUtil.getOrderNo());
        order.setCreatedAt(LocalDateTime.now());
        order.setUpdatedAt(LocalDateTime.now());
        order.setStatus(OrderStatusEnum.MATCHING);
        order.setSenderReceiverId(senderReceiver.getId());
        order.setTotalWeight(vo.getTotalWeight());
        order.setDistance(vo.getDistance());
        order.setTotalWorth(vo.getTotalWorth());
        order.setIsRefrigerated(vo.getIsRefrigerated());
        order.setIsInsurance(vo.getIsInsurance());
        order.setIsUrgent(vo.getIsUrgent());
        if (vo.getBillId()!= null){
            order.setBillId(vo.getBillId());
        }
        if (vo.getVehicleId() != null) {
            order.setVehicleId(vo.getVehicleId());
        }
        // 生成订单
        orderMapper.insert(order);
        //生成订单详情
        List<OrderItem> orderItem = vo.getOrderItems();
        for (OrderItem item : orderItem) {
            item.setOrderId(order.getId());
            orderItemService.add(item);
        }
        // 发布到广场
        String json = JSONObject.toJSONString(order);
        redisTemplate.opsForValue().set("order_info_" + order.getOrderNo(), json, TIMEOUT, TimeUnit.SECONDS);
    }
    @Resource
    private RabbitTemplate rabbitTemplate;
    /**
     * 秒杀(抢单)
     */
    @Resource
    private Redisson redisson;
    @Resource
    private updateStatusService updateStatusService;
    private static final String LOCK_KEY = "kill_lock";
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean killOrder(OtherDriverVo vo) {
        System.out.println("参数:" + vo);
        RLock lock = redisson.getLock(LOCK_KEY);
        try {
            lock.lock();
            String orderNo = vo.getOrderNo();
            String json = (String) redisTemplate.opsForValue().get("order_info_"+ orderNo);
            Order order = JSONObject.parseObject(json, Order.class);
            System.out.println("获取到订单信息:" + order);
            if (order == null) {
                return false;
            }
            if (order.getStatus() != OrderStatusEnum.MATCHING) {
                return false;
            }
            if(vo.getVehicleTypeId()!=null){
                PricingRuleVo pricingRuleVo = new PricingRuleVo();
                pricingRuleVo.setDistance(order.getDistance());
                pricingRuleVo.setVehicle_type_id(vo.getVehicleTypeId());
                // 获取单价
                BigDecimal unitPrice = pricingRuleService.getUnitPrice(pricingRuleVo);

                Bill bill = addBill(order.getIsUrgent(), order.getIsInsurance(), order.getIsRefrigerated(), order.getTotalWorth(), order.getDistance(), unitPrice);
                billService.add(bill);
                order.setBillId(bill.getId());
            }
            //更改状态
            order.setStatus(OrderStatusEnum.PENDING);
            // 更新司机和车辆信息
            order.setDriverId(vo.getDriverId());
            order.setVehicleId(vo.getVehicleId());
            //更新订单
            orderMapper.updateById(order);

            //更新司机和车辆状态
            updateStatusService.updateDriverAndVehicleStatusOfAfterStartOrder(order.getVehicleId(), order.getDriverId());
            String Email = updateStatusService.findDriverTypeAndEmail(order.getDriverId());
            if (Email != null){
                Message message = new Message();
                message.setToEmail(Email);
                message.setMessage("您好，已经为你分配新的订单,请及时完成运输");

                rabbitTemplate.convertAndSend("email-Queue","", message);
            }
            System.out.println("更新后的信息:" + order);
            redisTemplate.delete("order_info_" + orderNo);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            throw new KillException("系统繁忙，请稍后再试");
        } finally {
            lock.unlock();
        }
    }

    /**
     * 获取redis中的订单池列表
     * @return
     */
    @Override
    public List<OrderVo> getKillList() {
        Set<String> keys = redisTemplate.keys("order_info_*");
        List<Object> data = null;
        if (keys != null) {
            data = redisTemplate.opsForValue().multiGet(keys);
        }
        if (data != null) {
            return data.stream().map(item -> JSONObject.parseObject(item.toString(), OrderVo.class)).collect(Collectors.toList());
        }
        return null;
    }
    @Resource
    private SenderReceiverMapper senderReceiverMapper;
    /**
     * 完成订单
     * @param orderNo
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void finishOrder(String orderNo) {
        //查询订单信息
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Order::getOrderNo, orderNo);
        Order order = orderMapper.selectOne(queryWrapper);
        //给收货人发送邮件
        LambdaQueryWrapper<SenderReceiver> senderReceiverQueryWrapper = new LambdaQueryWrapper<>();
        senderReceiverQueryWrapper.eq(SenderReceiver::getId, order.getSenderReceiverId());
        SenderReceiver senderReceiver = senderReceiverMapper.selectOne(senderReceiverQueryWrapper);
        feignTransportService.sendEmail(senderReceiver.getReceiverEmail());
        //更新订单状态
        LambdaUpdateWrapper<Order> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Order::getOrderNo, orderNo)
                .set(Order::getStatus, OrderStatusEnum.FINISH);
        orderMapper.update(updateWrapper);
        //更新司机和车辆状态
        updateStatusService.updateDriverAndVehicleStatus(order.getVehicleId());
    }

    /**
     * 订单匹配超时无人抢单
     * @param orderNo
     */
    @Override
    public void updateOrderStatusByOrderNo(String orderNo) {
        LambdaUpdateWrapper<Order> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Order::getOrderNo, orderNo)
                .set(Order::getStatus, OrderStatusEnum.TIME_OUT);
        orderMapper.update(updateWrapper);
    }

    /**
     * 重新匹配
     * @param orderNo
     */
    @Override
    public void matchAgain(String orderNo) {
        //更新订单状态
        LambdaUpdateWrapper<Order> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Order::getOrderNo, orderNo)
                .set(Order::getStatus, OrderStatusEnum.MATCHING);
        orderMapper.update(updateWrapper);
        //添加到redis
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Order::getOrderNo, orderNo);
        Order order = orderMapper.selectOne(queryWrapper);
        String json = JSONObject.toJSONString(order);
        redisTemplate.opsForValue().set("order_info_" + order.getOrderNo(), json, TIMEOUT, TimeUnit.SECONDS);
    }

    public static Bill addBill(Boolean isUrgent, Boolean isInsurance, Boolean isRefrigerated, BigDecimal totalWorth, BigDecimal distance, BigDecimal unitPrice) {
        //获取总费用
        BigDecimal totalCost = new BigDecimal("0.0");
        // 生成账单
        System.out.println("单价" + unitPrice);
        //基础费用
        BigDecimal baseCost = unitPrice.multiply(distance).setScale(2, RoundingMode.HALF_UP);
        System.out.println("基础" + baseCost);
        //冷藏费用
        BigDecimal RefrigeratedCost = new BigDecimal("0.0");
        if (isRefrigerated) {
            RefrigeratedCost = baseCost.multiply(new BigDecimal("0.1")).setScale(2, RoundingMode.HALF_UP);
            System.out.println("冷藏" + RefrigeratedCost);
        }
        ;
        //保险费用
        BigDecimal InsuranceCost = new BigDecimal("0.0");
        if (isInsurance) {
            InsuranceCost = totalWorth.multiply(new BigDecimal("0.03")).setScale(2, RoundingMode.HALF_UP);
            System.out.println("保险" + InsuranceCost);
        }
        ;
        //加急费用
        BigDecimal UrgentCost = new BigDecimal("0.0");
        if (isUrgent) {
            UrgentCost = baseCost.multiply(new BigDecimal("0.1")).setScale(2, RoundingMode.HALF_UP);
            System.out.println("加急" + UrgentCost);
        }
        ;
        //总费用
        totalCost = totalCost.add(RefrigeratedCost).add(InsuranceCost).add(UrgentCost).add(baseCost);
        return Bill.builder()
                .payStatus(PayStatusEnum.NOT_PAY)
                .totalCost(totalCost)
                .baseCost(baseCost)
                .refrigerationFee(RefrigeratedCost)
                .urgentFee(UrgentCost)
                .insuranceFee(InsuranceCost).build();
    }

}
